﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace DARE
{
    [AttrTypeDependentSerializable(typeof(CDirectionalParticleData))]
    public class CDirectionalParticle: IParticle
    {
        #region fields

        private static VertexBuffer m_vertexBuffer = null;
        private static IndexBuffer m_indexBuffer = null;
        private float m_age = 0;

        #endregion

        #region properties

        public VertexBuffer VertexBuffer
        {
            get
            {
                if (m_vertexBuffer != null)
                    return m_vertexBuffer;

                VertexPositionColorTexture[] vertices = new VertexPositionColorTexture[4]
                {
                    new VertexPositionColorTexture(new Vector3(-0.5f, 0.5f, 0), Color.White, new Vector2(0, 0)),
                    new VertexPositionColorTexture(new Vector3(0.5f, 0.5f, 0), Color.White,new Vector2(1, 0)),
                    new VertexPositionColorTexture(new Vector3(-0.5f, -0.5f, 0), Color.White,new Vector2(0, 1)),
                    new VertexPositionColorTexture(new Vector3(0.5f, -0.5f, 0), Color.White,new Vector2(1, 1))
                };
                m_vertexBuffer = new VertexBuffer(CDare.Instance.GraphicsDevice, typeof(VertexPositionColorTexture), 4, BufferUsage.None);
                m_vertexBuffer.SetData<VertexPositionColorTexture>(vertices);
                return m_vertexBuffer;
            }
        }

        public IndexBuffer IndexBuffer
        {
            get
            {
                if (m_indexBuffer != null)
                    return m_indexBuffer;
                short[] indices = new short[6] { 0, 3, 1, 0, 2, 3 };
                m_indexBuffer = new IndexBuffer(CDare.Instance.GraphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.None);
                m_indexBuffer.SetData<short>(indices);
                return m_indexBuffer;
            }
        }

        public float LifeTime { get; set; }
        public float FadeInDuration { get; set; }
        public float FadeOutDuration { get; set; }
        public Color InitialColor { get; set; }
        public Color FinalColor { get; set; }
        public Vector2 InitialSize { get; set; }
        public Vector2 FinalSize { get; set; }
        public Effect ParticleEffect { get; set; }
        public Texture2D Texture { get; set; }
        public Vector3 Velocities { get; set; }
        public Vector3 Position { get; set; }
        public Vector3 Forces { get; set; }
        public bool IsAlive { get; set; }
        public float Age { get { return m_age; } }
        public Matrix WorldMatrix { get { return m_world; } }
        private Matrix m_world;
        #endregion

        #region ctor

        public CDirectionalParticle()
        {
#if WINDOWS_PHONE
            ParticleEffect = new BasicEffect(DARE.CDare.Instance.GraphicsDevice);
#else

            ParticleEffect = CResourceMgr.Load<Effect>("Shaders/Particle");
#endif
            m_vertexBuffer = VertexBuffer;
            m_indexBuffer = IndexBuffer;


            LifeTime = 200;
            FadeInDuration = 100;
            FadeOutDuration = 100;
            InitialColor = Color.White;
            FinalColor = Color.White;
            InitialSize = Vector2.One;
            FinalSize = Vector2.One;
            Velocities = Vector3.One * .0001f;
            Forces = Vector3.Zero;

        }

        #endregion

        #region methods

        /// <summary>
        /// Clones the particle entirely (returns a new particle)
        /// </summary>
        public IParticle Clone()
        {
            CDirectionalParticle directionalParticle = new CDirectionalParticle();
            directionalParticle.CloneParameters(this);
            return directionalParticle;
        }

        /// <summary>
        /// Clones only the parameters from the referenceParticle to the current particle
        /// </summary>
        public IParticle CloneParameters(IParticle referenceParticle)
        {
            if (referenceParticle is CDirectionalParticle)
            {
                CDirectionalParticle part = (referenceParticle as CDirectionalParticle);
                LifeTime = part.LifeTime;
                FadeInDuration = part.FadeInDuration;
                FadeOutDuration = part.FadeOutDuration;
                InitialColor = part.InitialColor;
                FinalColor = part.FinalColor;
                InitialSize = part.InitialSize;
                FinalSize = part.FinalSize;
                ParticleEffect = part.ParticleEffect;
                Texture = part.Texture;
                Velocities = part.Velocities;
                Position = part.Position;
                Forces = part.Forces;
                IsAlive = part.IsAlive;
            }
            return this;
        }

        /// <summary>
        /// Called whenever a particle is placed from the dead particles list to the active particle list
        /// </summary>
        public void Start()
        {
            m_age = 0;
            IsAlive = true;
        }
        Vector3 m_scale = new Vector3(1, 1, 1);
        Vector3 tmp = Vector3.Zero;
        public void Update(float elapsedTime)
        {
            if (!IsAlive)
                return;
            if (CDare.Instance.SceneMgr.ActiveScene == null || CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D == null)
                return;
            m_age += elapsedTime;
            if (m_age > LifeTime)
                IsAlive = false;
            tmp = Position;
            tmp.X += Velocities.X * elapsedTime;
            tmp.Y += Velocities.Y * elapsedTime;
            tmp.Z += Velocities.Z * elapsedTime;
            Position = tmp;
            tmp = Velocities;
            tmp.X += Forces.X * elapsedTime;
            tmp.Y += Forces.Y * elapsedTime;
            tmp.Z += Forces.Z * elapsedTime;
            Velocities = tmp;
            float ageOnLf = m_age / LifeTime;
            m_scale.X = MathHelper.Lerp(InitialSize.X, FinalSize.X, ageOnLf);
            m_scale.Y = MathHelper.Lerp(InitialSize.Y, FinalSize.Y, ageOnLf);
            m_scale.Z = 0;

            Matrix scale = Matrix.CreateScale(m_scale);
            CCamera cam = CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera;
            Matrix billboard = Matrix.CreateBillboard(Position, cam.Position, Vector3.Normalize(Velocities), Vector3.Normalize(cam.Target));

            m_world = scale * billboard;
        }

        public void Draw()
        {

            
#if WINDOWS_PHONE
            BasicEffect be = ParticleEffect as BasicEffect;

            be.World = m_world;
            be.View = CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera.View;
            be.Projection = CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera.Projection;
            be.Texture = Texture;
            be.TextureEnabled = true;

            float percent = m_age / LifeTime;
            Color color = Color.Lerp(InitialColor, FinalColor, percent);
            

            float alphaFactor = 1;
            float fin = FadeInDuration;
            float fout = FadeOutDuration;
            if (fin + fout > LifeTime)
                fin = fout = LifeTime / 2.0f;
            if (m_age <= fin)
                alphaFactor = m_age / fin;
            else if (LifeTime - m_age < fout)
                alphaFactor = (((LifeTime - m_age) / fout));

            color = new Color(color.R, color.G, color.B, alphaFactor);
            be.EmissiveColor = color.ToVector3();
            be.Alpha = color.A;
            ParticleEffect = be;
            CDare.Instance.GraphicsDevice.SetVertexBuffer(m_vertexBuffer);
            CDare.Instance.GraphicsDevice.Indices = m_indexBuffer;

            be.CurrentTechnique.Passes[0].Apply();
            CDare.Instance.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2);
#else
            //ParticleEffect.Parameters["World"].SetValue(Matrix.Identity);
            ParticleEffect.Parameters["View"].SetValue(CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera.View);
            ParticleEffect.Parameters["Projection"].SetValue(CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera.Projection);
            ParticleEffect.Parameters["UserTexture"].SetValue(Texture);
            ParticleEffect.Parameters["lifeTime"].SetValue(LifeTime);
            ParticleEffect.Parameters["FadingColor"].SetValue(FinalColor.ToVector4());
            ParticleEffect.Parameters["InitialColor"].SetValue(InitialColor.ToVector4());
            ParticleEffect.Parameters["FadeIn"].SetValue(FadeInDuration);
            ParticleEffect.Parameters["FadeOut"].SetValue(FadeOutDuration);
            CCamera cam = CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera;
            ParticleEffect.Parameters["CamPosition"].SetValue(cam.Position);
            ParticleEffect.Parameters["CamTarget"].SetValue(cam.Target);
#endif
        }

        #endregion
    }
}
